package edu.chalmers.AV_2DPlatformerMyGame.Model;

import edu.chalmers.AV_2DPlatformerFramework.Control.KBListener;
import edu.chalmers.AV_2DPlatformerFramework.Model.Game;
import edu.chalmers.AV_2DPlatformerFramework.View.Camera;
import edu.chalmers.AV_2DPlatformerFramework.Model.GameMap;
import edu.chalmers.AV_2DPlatformerFramework.Model.GameModel;
import edu.chalmers.AV_2DPlatformerFramework.Model.GameObject;
import edu.chalmers.AV_2DPlatformerFramework.Model.GameWorld;
import edu.chalmers.AV_2DPlatformerFramework.Model.Hitbox;
import edu.chalmers.AV_2DPlatformerFramework.Model.ObjectMover;
import edu.chalmers.AV_2DPlatformerFramework.Model.TileTexture;
import edu.chalmers.AV_2DPlatformerFramework.Utility.Pair;
import edu.chalmers.AV_2DPlatformerFramework.Utility.Vector2D;
import edu.chalmers.AV_2DPlatformerFramework.Utility.VectorUtility;
import java.awt.event.KeyEvent;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;

/**
 * @version 0.3
 * @author Andrea Buchholz
 * @revised Joakim Karlsson 20140522
 * @revised Andrea Buchholz 20140522
 * @revised Andrea Buchholz 20140524
 */
public class MyGameModel extends GameModel {
    
    private final KBListener kbListener;
    private final Vector2D playerAcceleration;
    private boolean onSurface = false;
    private final GameObject player;
    private final GameObject gobj2;
    private final GameObject gobj3;
    private final GameObject gobj4;
    private final GameObject gobj5;
    
    /**
     * 
     * @param g
     * @param c
     * @throws Hitbox.HitboxMalformedException
     */
    public MyGameModel(Game g, Camera c) throws Hitbox.HitboxMalformedException{
        super();
        kbListener = g.getKeyListener();
        
        GameObject gobj1 = new Object_Edmund();
        this.player = gobj1;
        this.gobj2 = new Object_Bench();
        this.gobj3 = new Object_Pill();
        this.gobj4 = new Object_Box();
        this.gobj5 = new Object_MathDude();
        
        gobj1.setVelocity(new Vector2D(0.5, 0.1));
        gobj2.setVelocity(new Vector2D(-0.7, -0.35));
        gobj3.setVelocity(new Vector2D(0.2, 1));
        gobj5.setVelocity(new Vector2D(3, 0));
        
        gobj1.setPosition(new Vector2D(50, 500));
        gobj2.setPosition(new Vector2D(700, 550));
        gobj3.setPosition(new Vector2D(500, 577));
        gobj4.setPosition(new Vector2D(1000, 566));
        gobj5.setPosition(new Vector2D(1200, 400));
        
                
        GameObject[] uniqueObjects = {
                                        gobj1,
                                        gobj2,
                                        gobj3,
                                        gobj4,
                                        gobj5
                                     };

        
        this.maps = new ArrayList<>();       
        GameWorld gw = new GameWorld    (new int[][] {
                                            {0, 500,    700, 800,   800, 850,    850, 1000},
                                            {0,   0,     -120, -120,    -90, -90,    -60, -60}},
                                            new Vector2D(0, 600)
                                         );
        gw.addTexture(new TileTexture(".\\src\\main\\java\\Textures\\dirtTile.jpg", null));
        playerAcceleration = new Vector2D(0, 0);
        this.maps = new ArrayList<>();
        this.maps.add(new GameMap(uniqueObjects, gw)); 
        this.maps.get(0).setMainActor(gobj1);
    }
    
     public void finishedLevel(){
        //TODO: om map är slut, kontrollera så att grandchildren >=3;
        //getPills() >=3
    }
    
    /**
     * //TODO Not fully functional yet!
     * Updates variable onSurface on whether or not player is on a surface.
     */
    public void onSurface(){
        
        GameObject[] objects = {gobj2, gobj3, gobj4, gobj5};
        
        for(GameObject object: objects){
            
            int playerY = (int)player.getPosition().getY();
            int playerX = (int)player.getPosition().getX();
            int objectY = (int)object.getPosition().getY();
            int objectX = (int)object.getPosition().getX();
            Rectangle2D playerEdges = player.getHitbox().getBounds2D();
            Rectangle2D objectEdges = object.getHitbox().getBounds2D();
            
            if( playerY+ playerEdges.getMaxY() >= objectY){
                if((playerX <= objectX + objectEdges.getMaxX()) || 
                        (playerX + playerEdges.getMaxX() >= objectX)){
                    onSurface = true;
                } 
            }
            else{
                onSurface = false;
            }
        }
    }  
     
    /**
     * 
     * @param e
     */
    public void characterMove(){
       
        if(kbListener.getQueueSize() > 0){
            Queue queue = kbListener.getQueue();
            KeyEvent e = (KeyEvent) queue.poll();
            int keyCode = e.getKeyCode();
            
            if((int) player.getPosition().getY() >= 499){
                onSurface = true;
            }
                  
            if(keyCode == KeyEvent.VK_DOWN){
              //TODO crouch/nothing?
            }
        
            if(keyCode == KeyEvent.VK_UP) {
                if(onSurface){
//                    player.setVelocity(VectorUtility.add(player.getVelocity(),
//                        new Vector2D(player.getVelocity().getX(), -4)));
                    player.setVelocity(new Vector2D(player.getVelocity().getX(),-4));
                    onSurface = false;
                }
            }
        
            if(keyCode == KeyEvent.VK_LEFT){
                //playerAcceleration = new Vector2D(-0.01, 0);
              // player.setCurrentTexture(1);
               if(onSurface){
                   // Not finished
                   // Accelerate when travelling in one direction.
//                   double acceleration = 0.2;
//                   KeyEvent next = (KeyEvent) queue.peek();
//                   int nextCode = next.getKeyCode();
//                   if(nextCode == KeyEvent.VK_LEFT){
//                       double vx = player.getVelocity().getX();
//                       vx -= acceleration;
//                       player.setVelocity(new Vector2D(vx, player.getVelocity().getY()));
//                    }
//                    else{
                        player.setVelocity(new Vector2D(-1, 0));
                    } 
               else{
                    player.setVelocity(new Vector2D(-1, player.getVelocity().getY()));
               }  
            }
        
            if(keyCode == KeyEvent.VK_RIGHT){
                 //player.setCurrentTexture(0);
                 double gravity = 0.08;
                 
                 if(onSurface){
                    player.setVelocity(new Vector2D(1, -gravity));
                 }
                 else{  
                    player.setVelocity(new Vector2D(1, player.getVelocity().getY()));
               }
//              playerAcceleration = new Vector2D(0.01, 0);
                                              
//                Vector2D oldV = player.getVelocity();
//                double newX = oldV.getX()*acceleration;
//                this.player.setVelocity(new Vector2D(newX,oldV.getY()));
                //if(animation right, else switch)
            }
      
//            if(keyCode == KeyEvent.VK_SPACE){
//                if(animation attack, else switch)
//                //onCollision differ
//            }
        }
    }
    
    
    //Denna behövs ej om vi ej använder acceleration.
    @Override
    public void moveActiveObjects() {
        ArrayList<GameObject> actors = maps.get(
                currentMapIndex).getObjects();
        Vector2D grav = maps.get(currentMapIndex).getGravity();
        Pair[] moves = new Pair[actors.size()];
        
        int i = 0;
        for(GameObject go : actors){
            if(go == player) {
                moves[i] = new Pair(
                        go, VectorUtility.add(grav, playerAcceleration));
                i++;
            } else {
                moves[i] = new Pair(go, grav);
                i++;
            }
        }
        ObjectMover.moveObjects(moves, actors);
        
    }
  
    @Override
    public synchronized void run() {   
        characterMove();
        moveActiveObjects();
    }
}